* All GdkWindows (native or not) track the position of the window in the parent
* (x, y), the size of the window (width, height), the position of the window
* with respect to the impl window (abs_x, abs_y). We also track the clip
- * region of the window wrt parent windows and siblings, in window-relative
- * coordinates with and without child windows included (clip_region,
- * clip_region_with_children).
+ * region of the window wrt parent windows, in window-relative coordinates (clip_region).
*
* All toplevel windows are native windows, but also child windows can be
* native (although not children of offscreens). We always listen to
const GdkRectangle *rect,
gboolean invalidate_children,
ClearBg clear_bg);
-static void _gdk_window_propagate_has_alpha_background (GdkWindow *window);
static cairo_surface_t *gdk_window_ref_impl_surface (GdkWindow *window);
static void gdk_window_set_frame_clock (GdkWindow *window,
if (window->devices_inside)
g_list_free (window->devices_inside);
- if (window->layered_region)
- cairo_region_destroy (window->layered_region);
-
G_OBJECT_CLASS (parent_class)->finalize (object);
}
return window->impl_window != window;
}
-static gboolean
-gdk_window_has_alpha (GdkWindow *window)
-{
- return !gdk_window_has_impl (window) &&
- (window->has_alpha_background || window->alpha != 255);
-}
-
static void
-remove_layered_child_area (GdkWindow *window,
- cairo_region_t *region)
+remove_sibling_overlapped_area (GdkWindow *window,
+ cairo_region_t *region)
{
- GdkWindow *child;
+ GdkWindow *parent;
+ GdkWindow *sibling;
cairo_region_t *child_region;
GdkRectangle r;
GList *l;
+ cairo_region_t *shape;
- for (l = window->children; l; l = l->next)
+ parent = window->parent;
+
+ if (parent == NULL)
+ return;
+
+ /* Convert from from window coords to parent coords */
+ cairo_region_translate (region, window->x, window->y);
+
+ for (l = parent->children; l; l = l->next)
{
- child = l->data;
+ sibling = l->data;
- /* If region is empty already, no need to do
- anything potentially costly */
- if (cairo_region_is_empty (region))
+ if (sibling == window)
break;
- if (!GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
+ if (!GDK_WINDOW_IS_MAPPED (sibling) || sibling->input_only || sibling->composited)
continue;
/* Ignore offscreen children, as they don't draw in their parent and
* don't take part in the clipping */
- if (gdk_window_is_offscreen (child))
- continue;
-
- /* Only non-impl children with alpha add to the layered region */
- if (!gdk_window_has_alpha (child))
+ if (gdk_window_is_offscreen (sibling))
continue;
- r.x = child->x;
- r.y = child->y;
- r.width = child->width;
- r.height = child->height;
-
- /* Bail early if child totally outside region */
- if (cairo_region_contains_rectangle (region, &r) == CAIRO_REGION_OVERLAP_OUT)
- continue;
+ r.x = sibling->x;
+ r.y = sibling->y;
+ r.width = sibling->width;
+ r.height = sibling->height;
child_region = cairo_region_create_rectangle (&r);
- if (child->shape)
+
+ if (sibling->shape)
{
/* Adjust shape region to parent window coords */
- cairo_region_translate (child->shape, child->x, child->y);
- cairo_region_intersect (child_region, child->shape);
- cairo_region_translate (child->shape, -child->x, -child->y);
+ cairo_region_translate (sibling->shape, sibling->x, sibling->y);
+ cairo_region_intersect (child_region, sibling->shape);
+ cairo_region_translate (sibling->shape, -sibling->x, -sibling->y);
+ }
+ else if (window->window_type == GDK_WINDOW_FOREIGN)
+ {
+ shape = GDK_WINDOW_IMPL_GET_CLASS (sibling)->get_shape (sibling);
+ if (shape)
+ {
+ cairo_region_intersect (child_region, shape);
+ cairo_region_destroy (shape);
+ }
}
cairo_region_subtract (region, child_region);
cairo_region_destroy (child_region);
}
+
+ /* Convert back to window coords */
+ cairo_region_translate (region, -window->x, -window->y);
}
static void
remove_child_area (GdkWindow *window,
- GdkWindow *until,
gboolean for_input,
- cairo_region_t *region,
- cairo_region_t *layered_region)
+ cairo_region_t *region)
{
GdkWindow *child;
cairo_region_t *child_region;
{
child = l->data;
- if (child == until)
- break;
-
/* If region is empty already, no need to do
anything potentially costly */
if (cairo_region_is_empty (region))
}
}
- if (gdk_window_has_alpha (child))
- {
- if (layered_region != NULL)
- cairo_region_union (layered_region, child_region);
- }
- else
- cairo_region_subtract (region, child_region);
+ cairo_region_subtract (region, child_region);
cairo_region_destroy (child_region);
}
}
r.height = window->height;
region = cairo_region_copy (window->clip_region);
- if (window->layered_region)
- cairo_region_subtract (region, window->layered_region);
+ remove_sibling_overlapped_area (window, region);
/* We only apply the clip region if would differ
from the actual clip region implied by the size
GdkRectangle r;
GList *l;
GdkWindow *child;
- cairo_region_t *new_clip, *new_layered;
+ cairo_region_t *new_clip;
gboolean clip_region_changed;
gboolean abs_pos_changed;
int old_abs_x, old_abs_y;
/* Update clip region based on:
* parent clip
- * window size
- * siblings in parents above window
+ * window size/position
*/
clip_region_changed = FALSE;
if (recalculate_clip)
{
- new_layered = cairo_region_create ();
if (private->viewable)
{
/* Calculate visible region (sans children) in parent window coords */
new_clip = cairo_region_create_rectangle (&r);
if (!gdk_window_is_toplevel (private))
- {
- cairo_region_intersect (new_clip, private->parent->clip_region);
- cairo_region_union (new_layered, private->parent->layered_region);
-
- /* Remove all overlapping children from parent. */
- remove_child_area (private->parent, private, FALSE, new_clip, new_layered);
- }
+ cairo_region_intersect (new_clip, private->parent->clip_region);
/* Convert from parent coords to window coords */
cairo_region_translate (new_clip, -private->x, -private->y);
- cairo_region_translate (new_layered, -private->x, -private->y);
if (private->shape)
cairo_region_intersect (new_clip, private->shape);
else
new_clip = cairo_region_create ();
- cairo_region_intersect (new_layered, new_clip);
-
if (private->clip_region == NULL ||
!cairo_region_equal (private->clip_region, new_clip))
clip_region_changed = TRUE;
- if (private->layered_region == NULL ||
- !cairo_region_equal (private->layered_region, new_layered))
- clip_region_changed = TRUE;
-
if (private->clip_region)
cairo_region_destroy (private->clip_region);
private->clip_region = new_clip;
-
- if (private->layered_region != NULL)
- cairo_region_destroy (private->layered_region);
- private->layered_region = new_layered;
-
- if (private->clip_region_with_children)
- cairo_region_destroy (private->clip_region_with_children);
- private->clip_region_with_children = cairo_region_copy (private->clip_region);
- if (private->window_type != GDK_WINDOW_ROOT)
- remove_child_area (private, NULL, FALSE, private->clip_region_with_children, NULL);
}
if (clip_region_changed)
/* XXX: Cache this somehow? */
window->background = cairo_pattern_create_rgba (0, 0, 0, 0);
- window->has_alpha_background = TRUE;
}
else
{
_gdk_window_update_viewable (window);
- if (window->background == NULL)
- {
- /* parent relative background, update has_alpha_background */
- if (window->parent == NULL ||
- window->parent->window_type == GDK_WINDOW_ROOT)
- window->has_alpha_background = FALSE;
- else
- window->has_alpha_background = window->parent->has_alpha_background;
- }
-
recompute_visible_regions (window, TRUE, FALSE);
if (old_parent && GDK_WINDOW_TYPE (old_parent) != GDK_WINDOW_ROOT)
recompute_visible_regions (old_parent, FALSE, TRUE);
- _gdk_window_propagate_has_alpha_background (window);
-
/* We used to apply the clip as the shape, but no more.
Reset this to the real shape */
if (gdk_window_has_impl (window) &&
if (gdk_window_is_viewable (window))
impl_class->show (window, FALSE);
+ gdk_window_invalidate_in_parent (window);
+
return TRUE;
}
cairo_region_destroy (window->clip_region);
window->clip_region = NULL;
}
-
- if (window->clip_region_with_children)
- {
- cairo_region_destroy (window->clip_region_with_children);
- window->clip_region_with_children = NULL;
- }
}
break;
}
paint = l->data;
- region = cairo_region_copy (window->clip_region_with_children);
+ region = cairo_region_copy (window->clip_region);
cairo_region_translate (region, window->abs_x, window->abs_y);
/* Anything in the whole flushed window that was drawn is now
paint = g_new (GdkWindowPaint, 1);
paint->region = cairo_region_copy (region);
- cairo_region_intersect (paint->region, window->clip_region_with_children);
+ cairo_region_intersect (paint->region, window->clip_region);
cairo_region_get_extents (paint->region, &clip_box);
cairo_region_translate (paint->region, window->abs_x, window->abs_y);
by being drawn in back to front order. However, if implicit paints are not used, for
instance if it was flushed due to a non-double-buffered paint in the middle of the
expose we need to copy in the existing data here. */
- if (gdk_window_has_alpha (window) &&
- (!implicit_paint ||
- (implicit_paint && implicit_paint->flushed != NULL && !cairo_region_is_empty (implicit_paint->flushed))))
+ if (!implicit_paint ||
+ (implicit_paint && implicit_paint->flushed != NULL && !cairo_region_is_empty (implicit_paint->flushed)))
{
cairo_t *cr = cairo_create (paint->surface);
/* We can't use gdk_cairo_set_source_window here, as that might
{
cairo_t *cr;
- full_clip = cairo_region_copy (window->clip_region_with_children);
+ full_clip = cairo_region_copy (window->clip_region);
cairo_region_intersect (full_clip, paint->region);
cr = gdk_cairo_create (window);
if (!window->paint_stack)
{
- gdk_cairo_region (cr, window->clip_region_with_children);
+ gdk_cairo_region (cr, window->clip_region);
cairo_clip (cr);
}
else
end_implicit = gdk_window_begin_implicit_paint (window->impl_window, &clip_box, TRUE, window->alpha);
}
- /* Paint the window before the children, clipped to the window region
- with visible child windows removed */
+ /* Paint the window before the children, clipped to the window region */
clipped_expose_region = cairo_region_copy (expose_region);
- cairo_region_intersect (clipped_expose_region, window->clip_region_with_children);
+ cairo_region_intersect (clipped_expose_region, window->clip_region);
if (!cairo_region_is_empty (clipped_expose_region) &&
!window->destroyed)
if (impl_window->update_area)
{
- tmp_region = cairo_region_copy (window->clip_region_with_children);
+ tmp_region = cairo_region_copy (window->clip_region);
/* Convert to impl coords */
cairo_region_translate (tmp_region, window->abs_x, window->abs_y);
cairo_region_intersect (tmp_region, impl_window->update_area);
/* Convert from impl coords */
cairo_region_translate (tmp_region, -window->abs_x, -window->abs_y);
- /* Don't remove any update area that is overlapped by non-opaque windows
- (children or siblings) with alpha, as these really need to be repainted
- independently of this window. */
+ /* Don't remove any update area that is overlapped by sibling windows
+ or child windows as these really need to be repainted independently of this window. */
to_remove = cairo_region_copy (tmp_region);
- cairo_region_subtract (to_remove, window->parent->layered_region);
- remove_layered_child_area (window, to_remove);
+
+ remove_child_area (window, FALSE, to_remove);
+ remove_sibling_overlapped_area (window, to_remove);
/* Remove from update_area */
cairo_region_translate (to_remove, window->abs_x, window->abs_y);
}
-/* Updates has_alpha_background recursively for all child windows
- that have parent-relative alpha */
-static void
-_gdk_window_propagate_has_alpha_background (GdkWindow *window)
-{
- GdkWindow *child;
- GList *l;
-
- for (l = window->children; l; l = l->next)
- {
- child = l->data;
-
- if (child->background == NULL &&
- child->has_alpha_background != window->has_alpha_background)
- {
- child->has_alpha_background = window->has_alpha_background;
- recompute_visible_regions (child, TRUE, FALSE);
- _gdk_window_propagate_has_alpha_background (child);
- }
- }
-}
-
/**
* gdk_window_set_background_pattern:
* @window: a #GdkWindow
gdk_window_set_background_pattern (GdkWindow *window,
cairo_pattern_t *pattern)
{
- gboolean has_alpha;
- cairo_pattern_type_t type;
-
g_return_if_fail (GDK_IS_WINDOW (window));
if (window->input_only)
cairo_pattern_destroy (window->background);
window->background = pattern;
- has_alpha = TRUE;
-
- if (pattern == NULL)
- {
- /* parent-relative, copy has_alpha from parent */
- if (window->parent == NULL ||
- window->parent->window_type == GDK_WINDOW_ROOT)
- has_alpha = FALSE;
- else
- has_alpha = window->parent->has_alpha_background;
- }
- else
- {
- type = cairo_pattern_get_type (pattern);
-
- if (type == CAIRO_PATTERN_TYPE_SOLID)
- {
- double alpha;
- cairo_pattern_get_rgba (pattern, NULL, NULL, NULL, &alpha);
- if (alpha == 1.0)
- has_alpha = FALSE;
- }
- else if (type == CAIRO_PATTERN_TYPE_LINEAR ||
- type == CAIRO_PATTERN_TYPE_RADIAL)
- {
- int i, n;
- double alpha;
-
- n = 0;
- cairo_pattern_get_color_stop_count (pattern, &n);
- has_alpha = FALSE;
- for (i = 0; i < n; i++)
- {
- cairo_pattern_get_color_stop_rgba (pattern, i, NULL,
- NULL, NULL, NULL, &alpha);
- if (alpha != 1.0)
- {
- has_alpha = TRUE;
- break;
- }
- }
- }
- else if (type == CAIRO_PATTERN_TYPE_SURFACE)
- {
- cairo_surface_t *surface;
- cairo_content_t content;
-
- cairo_pattern_get_surface (pattern, &surface);
- content = cairo_surface_get_content (surface);
- has_alpha =
- (content == CAIRO_CONTENT_ALPHA) ||
- (content == CAIRO_CONTENT_COLOR_ALPHA);
- }
- }
-
- if (has_alpha != window->has_alpha_background)
- {
- window->has_alpha_background = has_alpha;
- recompute_visible_regions (window, TRUE, FALSE);
-
- _gdk_window_propagate_has_alpha_background (window);
- }
-
if (gdk_window_has_impl (window))
{
GdkWindowImplClass *impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
r.height = window->height;
region = cairo_region_create_rectangle (&r);
- remove_child_area (window, NULL, FALSE, region, NULL);
+ remove_child_area (window, FALSE, region);
if (merge && window->shape)
cairo_region_subtract (region, window->shape);
r.height = window->height;
region = cairo_region_create_rectangle (&r);
- remove_child_area (window, NULL, TRUE, region, NULL);
+ remove_child_area (window, TRUE, region);
if (merge && window->shape)
cairo_region_subtract (region, window->shape);
g_print (" alpha[%d]",
window->alpha);
- if (window->has_alpha_background)
- g_print (" alpha_bg");
-
s = print_region (window->clip_region);
g_print (" clipbox[%s]", s);